using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using System.Reflection;

//csc /debug /target:module "D:\frk\Projetos Software\UsiXML360\src\csharp\CSharpLogicConector\CSharpLogicConector\CSharpLogicConector.cs"

public class CSharpLogicConector
{
    static CSharpLogicConector instance = null;

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    static CSharpLogicConector()
    {
    }

    CSharpLogicConector()
    {
    }

    public static CSharpLogicConector Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new CSharpLogicConector();
            }

            return instance;
        }
    }

    private MethodDefinition currentMethod = null;

    public void initializeMethod()
    {
        this.currentMethod = null;
    }

    public void executeMethod()
    {
        this.getMethodDefinition().callMethod();
    }

    public double getMethodReturnDouble()
    {
        return this.getMethodDefinition().getDoubleReturnValue();
    }

    public int getMethodReturnInteger()
    {
        return this.getMethodDefinition().getIntegerReturnValue();
    }

    public String getMethodReturnString()
    {
        return this.getMethodDefinition().getStringReturnValue();
    }

    public void prepareMethodDoubleParameter(double parameter, int position)
    {
        this.getMethodDefinition().addParameter(parameter, position);
    }

    public void prepareMethodIntegerParameter(int parameter, int position)
    {
        this.getMethodDefinition().addParameter(parameter, position);
    }

    public void prepareMethodName(String methodName)
    {
        this.getMethodDefinition().setMethodName(methodName);
    }

    public void prepareMethodClass(String methodClass)
    {
        this.getMethodDefinition().setClassName(methodClass);
    }

    public void prepareMethodStringParameter(String parameter, int position)
    {
        this.getMethodDefinition().addParameter(parameter, position);
    }

    public void prepareMethodDoubleReturnParameter()
    {
        this.getMethodDefinition().setMethodReturnType(ParameterType.PARAMETER_DOUBLE);

    }

    public void prepareMethodIntegerReturnParameter()
    {
        this.getMethodDefinition().setMethodReturnType(ParameterType.PARAMETER_INTEGER);

    }

    public void prepareMethodStringReturnParameter()
    {
        this.getMethodDefinition().setMethodReturnType(ParameterType.PARAMETER_STRING);
    }

    private MethodDefinition getMethodDefinition()
    {
        if (this.currentMethod == null)
        {
            this.currentMethod = new MethodDefinition();
        }

        return this.currentMethod;
    }

    public class MethodDefinition
    {

        private String className;
        private String methodName;

        private System.Collections.Hashtable parametersDefinition = new Hashtable();
        private ParameterType returnType;

        private System.Collections.Hashtable integerParameter = new Hashtable();
        private System.Collections.Hashtable doubleParameter = new Hashtable();
        private System.Collections.Hashtable stringParameter = new Hashtable();

        private String returnString;
        private int returnInteger;
        private Double returnDouble;

        public MethodDefinition()
        {
        }

        public void setClassName(String name)
        {
            this.className = name;
        }

        public void setMethodName(String name)
        {
            this.methodName = name;
        }

        public void setMethodReturnType(ParameterType returnType)
        {
            this.returnType = returnType;
        }

        public void addParameter(String parameter, int position)
        {
            this.parametersDefinition.Add(position, ParameterType.PARAMETER_STRING);
            this.stringParameter.Add(position, parameter);
        }

        public void addParameter(int parameter, int position)
        {
            this.parametersDefinition.Add(position, ParameterType.PARAMETER_INTEGER);
            this.integerParameter.Add(position, parameter);
        }

        public void addParameter(Double parameter, int position)
        {
            this.parametersDefinition.Add(position, ParameterType.PARAMETER_DOUBLE);
            this.doubleParameter.Add(position, parameter);
        }

        public void callMethod()
        {
            if (this.className == null || this.methodName == null)
            {
                throw new InvalidOperationException("Class or method name not configured");
            }
            else
            {
                int numParameters = this.parametersDefinition.Count;
                ParameterType[] parameterTypeArray = new ParameterType[numParameters];
                Object[] parameterArray = new Object[numParameters];

                for (int i = 0; i < numParameters; i++)
                {
                    ParameterType parType = (ParameterType)this.parametersDefinition[i];

                    switch (parType)
                    {
                        case ParameterType.PARAMETER_DOUBLE:
                            parameterTypeArray[i] = ParameterType.PARAMETER_DOUBLE;
                            parameterArray[i] = this.doubleParameter[i];
                            break;
                        case ParameterType.PARAMETER_INTEGER:
                            parameterTypeArray[i] = ParameterType.PARAMETER_INTEGER;
                            parameterArray[i] = this.integerParameter[i];
                            break;
                        case ParameterType.PARAMETER_STRING:
                            parameterTypeArray[i] = ParameterType.PARAMETER_STRING;
                            parameterArray[i] = this.stringParameter[i];
                            break;
                        default:
                            throw new InvalidOperationException("");
                    }
                }

                Object obj = DomainModel.getInstance().getDomainModelObject(this.className);
                MethodInfo method = obj.GetType().GetMethod(this.methodName);

                Object returnValue = method.Invoke(obj, parameterArray);

                switch (this.returnType)
                {
                    case ParameterType.PARAMETER_DOUBLE:
                        this.returnDouble = (Double)returnValue;
                        break;
                    case ParameterType.PARAMETER_INTEGER:
                        this.returnInteger = (int)returnValue;
                        break;
                    case ParameterType.PARAMETER_STRING:
                        this.returnString = (String)returnValue;
                        break;
                    default:
                        throw new InvalidOperationException("");
                }

            }
        }

        public int getIntegerReturnValue()
        {

            if (this.returnType.CompareTo(ParameterType.PARAMETER_INTEGER) == 0)
            {
                return this.returnInteger;
            }
            else
            {
                throw new InvalidOperationException("Invalid method return type");
            }
        }

        public String getStringReturnValue()
        {

            if (this.returnType.CompareTo(ParameterType.PARAMETER_STRING) == 0)
            {
                return this.returnString;
            }
            else
            {
                throw new InvalidOperationException("Invalid method return type");
            }
        }

        public Double getDoubleReturnValue()
        {

            if (this.returnType.CompareTo(ParameterType.PARAMETER_DOUBLE) == 0)
            {
                return this.returnDouble;
            }
            else
            {
                throw new InvalidOperationException("Invalid method return type");
            }
        }

    }

    public enum ParameterType
    {
        PARAMETER_DOUBLE,
        PARAMETER_INTEGER,
        PARAMETER_STRING
    };

    public class DomainModel
    {
        private static DomainModel _instance;
        private Object currentObject = null;

        public static DomainModel getInstance()
        {
            if (_instance == null)
            {
                _instance = new DomainModel();
            }

            return _instance;
        }

        public Object getDomainModelObject(String className)
        {

            if (this.currentObject == null)
            {
                Assembly requestedClass = Assembly.LoadFrom("D:/frk/Projetos Software/UsiXML360/rsc/CsharpCalculator.dll");
                this.currentObject = requestedClass.CreateInstance(className);
            }

            return this.currentObject;
        }

    }


}


